package goroutine

import (
	"fmt"
	"sync"
)

func lockVal() {
	/*
	go语言没有volatile关键字，但内存可见性规则有一条：
	对任意 sync.Mutex 和 sync.RWMutex 的锁变量 L，第 n 次调用 L.Unlock() 逻辑先于
	（结果可见于）第 m 次调用 L.Lock() 操作。
	 */
	var mu sync.Mutex
	var count = 0
	var wg sync.WaitGroup
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func() {
			defer wg.Done()
			for j:=0;j<10000;j++{
				mu.Lock()
				count ++
				mu.Unlock()
			}
		}()
	}

	wg.Wait()
	fmt.Println("count=", count)

}




/**


go的设计者认为，如果需要重入锁，就说明你的代码写的有问题： https://stackoverflow.com/questions/14670979/recursive-locking-in-go#14671462

可以将代码按照作用范围分层，金字塔形，底部是各个小函数，上层调用下层的函数，越往上作用范围越大；各层有自己的锁，并只能在本层的函数中使用：同一个锁在不同层中使用就会导致重入

go的标准库里面的做法是将需要锁住的操作独立为函数并以Locked为后缀命名，然后在调用这些函数的地方用锁来保护:
func (b *body) Read(p []byte) (n int, err error) {
    b.mu.Lock()
    defer b.mu.Unlock()
    if b.closed {
        return 0, ErrBodyReadAfterClose
    }
    return b.readLocked(p)
}

// Must hold b.mu.
func (b *body) readLocked(p []byte) (n int, err error) {
    if b.sawEOF {
        return 0, io0.EOF
    }
    n, err = b.src.Read(p)

  ...
}


如果一定要实现可重入锁，就必须有类似goroutine id的东西，这可能也是go的设计者不提供goroutine id的原因



 */

func lock2Time(){
	var mu sync.Mutex
	var count = 0
	var wg sync.WaitGroup
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go func() {
			defer wg.Done()
			for j:=0;j<10000;j++{
				//对同一个锁，进行多次锁，会死锁
				mu.Lock()
				mu.Lock()
				count ++
				mu.Unlock()
			}
		}()
	}

	wg.Wait()
	fmt.Println("count=", count)



}


